<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class LockRequest
{
    private const LOCK_TIMEOUT = 5;

    private const IGNORE_URL = [
        '*/user/logout',
        '*/v1/withdraw',
        '*/v1/client-log',
    ];

    private const IGNORE_ROUTE = [
        'api.*.order.return',
        'api.*.order.notify',
        'api.*.withdrawOrder.notify',
    ];

    /**
     * 非 GET 请求时, 尝试获得锁
     * @param $request
     * @param Closure $next
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if ($request->getMethod() == 'GET') {
            return $next($request);
        }
        // 忽略URL
        foreach (self::IGNORE_URL as $rule) {
            if ($request->is($rule)) return $next($request);
        }
        // 忽略路由名
        foreach (self::IGNORE_ROUTE as $rule) {
            if ($request->routeIs($rule)) return $next($request);
        }

        $key = sprintf("%s:%s:%s", $request->getRequestUri(), $request->getMethod(), getClientIp());

        $user = $request->user();
        if ($user) $key = sprintf("%s:%d", $key, $user->id);

        $lock = Cache::lock($key, self::LOCK_TIMEOUT);
        if ($lock->get()) {
            $response = $next($request);
            $lock->release();
            return $response;
        }
        info(__METHOD__, [$key, '并发被拦截']);
        return responseException('操作太快, 停下来喝杯茶吧');
    }
}
